package edu.wpi.cs509.representation;

import java.io.Serializable;

/**                                                                             
 * Gameboard is the base class representing the physical game board, locations  
 * on the gameboard,player pieces, and current turn                             
 * Gameboard class has an association with the Game class.                      
 * Game class is the main class for a specific active game.                     
 * Game class contains the gameboard, each player, any observers,               
 * and the game ID number.   
 * @author Scott Sussman                                                   
 **/


public class Gameboard extends StrategoObjectBc implements Serializable {

	private static final long serialVersionUID = 1L; // Version of structure for messages.
	public static final int ROWS = 10;
	public static final int COLS = 10;
	public static final int PIECES = 40;
	public static final int MARSHALS = 1;
	public static final int GENERALS = 1;
	public static final int COLONELS = 2;
	public static final int MAJORS = 3;
	public static final int CAPTAINS = 4;
	public static final int LIEUTENANTS = 4;
	public static final int SERGEANTS = 4;
	public static final int MINERS = 5;
	public static final int SCOUTS = 8;
	public static final int SPYS = 1;
	public static final int FLAGS = 1;
	public static final int BOMBS  = 6;

	private Location boardsquare[][] = new Location[COLS][ROWS];
	private Location boneyard = new Location();

	private PlayerPiece redPieces[];
	private PlayerPiece bluePieces[];

	public boolean isClone=false;

	/** 
	 * constructor method for Gameboard class
	 * @param name
	 */
	public Gameboard(String name) {		
		super(name);

		initGameboardPieces();

		initBoardSquareLocations();

		initBoneyard();
	}

	public Gameboard(String name, boolean client) {
		super(name);

		redPieces = new PlayerPiece[PIECES];
		bluePieces = new PlayerPiece[PIECES];

		initBoardSquareLocations();
	}

	// init game pieces
	private void initGameboardPieces() {
		int index = 0,loop=0;

		redPieces = new PlayerPiece[PIECES];
		bluePieces = new PlayerPiece[PIECES];

		for (loop=0;loop < StrategoPiece.ALL_GAME_PIECES.length;loop++) {
			int pceCnt = StrategoPiece.ALL_GAME_PIECES[loop].numberPerUser();
			System.out.println("Create " + pceCnt + " " + StrategoPiece.ALL_GAME_PIECES[loop].toString());

			for (;pceCnt>0;pceCnt--) {
				redPieces[index] = new PlayerPiece(StrategoPiece.ALL_GAME_PIECES[loop], TeamColor.RED);
				bluePieces[index] = new PlayerPiece(StrategoPiece.ALL_GAME_PIECES[loop], TeamColor.BLUE);
				index++;
			}
		}
	}

	private void initBoardSquareLocations() {
		// Init boardsquare locations
		for (int y = 0; y < ROWS; y++) {
			for (int x = 0; x < COLS; x++) {
				boardsquare[x][y] = new Location(x, y);
			}
		}
	}

	private void initBoneyard() {
		// init boneyard for red and blue teams
		//place pieces in boneyard at init time
		int index = 0;

		for (index = 0;index<PIECES; index++) {
			redPieces[index].setLocation(boneyard);
			bluePieces[index].setLocation(boneyard);
		}	
	}


	protected Object clone(TeamColor mask) throws CloneNotSupportedException {
		Gameboard clonedBoard;
		Object cloneGb = super.clone();				
		clonedBoard = (Gameboard)cloneGb;
		clonedBoard.isClone = true;

		return cloneGb;
	}

	/**
	 * toString - return a string with the object's contents
	 */
	public String toString() {
		StringBuilder result = new StringBuilder();
		String NEW_LINE = System.getProperty("line.separator");

		result.append(this.getClass().getName() + " Object {" + NEW_LINE);


		String p00Name = "empty";
		String p10Name = "empty";
		String p20Name = "empty";
		String p79Name = "empty";
		String p89Name = "empty";
		String p99Name = "empty";
		
		try {
			PlayerPiece p = getPlayerPieceOnBoardSquare(0, 0);
			if (p != null)
				p00Name = p.getName();
		} catch (GameboardException e) {
			// do nothing
		}
		try {
			PlayerPiece p = getPlayerPieceOnBoardSquare(1, 0);
			if (p != null)
				p10Name = p.getName();
		} catch (GameboardException e) {
			// do nothing
		}
		try {
			PlayerPiece	p = getPlayerPieceOnBoardSquare(2, 0);
			if (p != null)
				p20Name = p.getName();
		} catch (GameboardException e) {
			// do nothing
		}

		try {
			PlayerPiece p = getPlayerPieceOnBoardSquare(7, 9);
			if (p != null)
				p79Name = p.getName();
		} catch (GameboardException e) {
			// do nothing
		}
		
		try {
			PlayerPiece p = getPlayerPieceOnBoardSquare(8, 9);
			if (p != null)
				p89Name = p.getName();
		} catch (GameboardException e) {
			// do nothing
		}

		try {
			PlayerPiece p = getPlayerPieceOnBoardSquare(9, 9);
			if (p != null)
				p99Name = p.getName();
		} catch (GameboardException e) {
			// do nothing
		}

		result.append(" boardsquare[x0][y0]:    " + boardsquare[0][0].toString() + p00Name + NEW_LINE);
		result.append(" boardsquare[x1][y0]:    " + boardsquare[1][0].toString() + p10Name + NEW_LINE);
		result.append(" boardsquare[x2][y0]:    " + boardsquare[2][0].toString() + p20Name + NEW_LINE);
		result.append(" boardsquare[x7][y9]:    " + boardsquare[7][9].toString() + p79Name + NEW_LINE);
		result.append(" boardsquare[x8][y9]:    " + boardsquare[8][9].toString() + p89Name + NEW_LINE);
		result.append(" boardsquare[x9][y9]:    " + boardsquare[9][9].toString() + p99Name + NEW_LINE);
		result.append("}");

		return result.toString();
	}

	/**
	 * get the board square object from the x,y coords
	 * @param x
	 * @param y
	 * @return boardsquare[x][y]
	 * @throws GameboardException
	 */
	public Location getBoardsquare(int x, int y) throws GameboardException {
		if (y >= ROWS) {
			throw new GameboardException();
		}
		if (x >= COLS) {
			throw new GameboardException();
		}
		return boardsquare[x][y];
	}

	/**
	 * get the board square object from the index. Boardsquare index is associated to the GUI index
	 * this allows the UI team to retrieve the boardsquare representation that maps to the GUI square
	 * @param boardIndex
	 * @return loc
	 * @throws GameboardException
	 */
	public Location getBoardsquareFromIndex(int index) throws GameboardException {
		Location loc = null;
		int y = index%10;
		int x = index/10;

		if (index<0 || index>99)
			throw new GameboardException();

		try {
			loc = getBoardsquare(x, y);
		}
		catch (GameboardException gbe) {
			System.out.println("- Saw a gameboard exception - Index not valid");
		}
		finally {
		}

		return loc;
	}


	/**
	 * getPlayerPieceOnBoardSquare - given x and y values find the piece in that location.
	 * if the location does not contain a piece return null.
	 * @param x
	 * @param y
	 * @return piece
	 * @throws GameboardException
	 */
	public PlayerPiece getPlayerPieceOnBoardSquare(int x, int y) throws GameboardException {
		int loop=0,myX=0,myY=0;
		PlayerPiece piece=null;

		if (y >= ROWS) {
			throw new GameboardException();
		}

		if (x >= COLS) {
			throw new GameboardException();
		}

		for (loop=0;loop<PIECES;loop++) {

			piece = redPieces[loop];
			myX = piece.location.x;
			myY = piece.location.y;

			if (y == myY && x == myX) {
				break;
			}

			piece = bluePieces[loop];
			myX = piece.location.x;
			myY = piece.location.y;

			if (y == myY && x == myX) {
				break;
			}

			piece = null;
		}

		return piece;
	}

	/** 
	 * getPlayerPieceInBoneyard - given the piece color and type find a matching piece object in the
	 * boneyard and return it.
	 * @param pieceColor
	 * @param pieceType
	 * @return piece
	 */
	public PlayerPiece getPlayerPieceInBoneyard(TeamColor pieceColor, StrategoPiece pieceType) {
		int index = 0;
		PlayerPiece piece=null;

		for (index = 0;index<PIECES; index++) {
			if (pieceColor.isRed()) {
				piece = redPieces[index];
			} else {
				piece = bluePieces[index];
			}

			if (piece.pieceType==pieceType && piece.location.boneyard) {
				break;
			}

			piece = null;
		}

		return piece;
	}

	/**
	 * Get the player piece with the given gameboard index that corresponds to the GUI square index
	 * @param boardIndex
	 * @return piece
	 * @throws GameboardException
	 */
	public PlayerPiece getPlayerPieceAtGameboardIndex(int boardIndex) throws GameboardException {
		PlayerPiece piece=null;

		if (boardIndex>99 || boardIndex<0) {
			throw new GameboardException();
		}

		for (int index = 0;index<PIECES; index++) {
			piece = redPieces[index];

			if (piece.location.index==boardIndex) {
				System.out.println("Found piece " + piece.toString() + " for " + piece.color + "Team");
				break;
			}

			piece = bluePieces[index];
			if (piece.location.index==boardIndex) {
				System.out.println("Found piece " + piece.toString() + " for " + piece.color + "Team");
				break;
			}	

			piece = null;
		}

		return piece;
	}

	/**
	 * getLocationFromPlayerPiece - return the location object associated to this player piece
	 * @param piece
	 * @return piece.location
	 */
	public Location getLocationFromPlayerPiece(PlayerPiece piece) {
		return piece.location;
	}

	/**
	 * getPieceFromLocation - Return the Player piece object given a board location object.
	 * @param loc
	 * @return pce
	 */
	public PlayerPiece getPlayerPieceFromLocation(Location loc) {
		PlayerPiece pce=null;

		try {
			pce = this.getPlayerPieceOnBoardSquare(loc.x,loc.y);
		}
		catch (GameboardException gbe) {
			System.out.println("- saw a gameboard exception - failed to find player piece on board square " + loc.x + "," + loc.y);    		
		}
		finally {
		}

		return pce;
	}

	/**
	 * getFullBoard - Gets the full boardsquare array of location objects
	 * @return baordsquare
	 */
	public Location[][] getFullBoard() {
		return boardsquare;
	}

	/**
	 * getBoneyard - Get the boneyard object.
	 * @return
	 */
	public Location getBoneyard() {
		return boneyard;
	}

	public PlayerPiece getPlayerPiece(TeamColor color,int index) {
		PlayerPiece piece = null;
		if (color == TeamColor.RED) {
			piece = this.redPieces[index];
		} else {
			piece = this.bluePieces[index];
		}
		return piece; 
	}

	public boolean setPlayerPiece(PlayerPiece newpce,TeamColor color,int index) {
		if (color.isRed==true) {
			this.redPieces[index] = newpce;
		} else {
			this.bluePieces[index] = newpce;
		}

		return true;
	}
}
